package com.hesicare.untils.sginutils;

import com.hesicare.health.entity.SysUser;
import com.hesicare.health.service.ISysUserService;
import net.coobird.thumbnailator.Thumbnails;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.imageio.ImageIO;
import javax.imageio.stream.FileImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.*;
import java.math.BigDecimal;
import java.util.Base64;

/**
 * @Author 55097
 * @create 2022/1/4 12:38
 */
public class imageThumbnailatorUtil {

    private final static Logger logger = LoggerFactory.getLogger(imageThumbnailatorUtil.class);

    @Autowired
    private ISysUserService ISysUserService;

    @Value("${sginUrl}")
    private String path;
    //static String path = "C:\\Users\\55097\\Desktop\\test";

    static int size = 1024;

    /**
     * 【压缩图片】到要求的图片标准:  宽[300,500],高[300,500];100kb;jpg/jpeg
     * 先按宽高压缩，压缩后如果还不满足100kb,则按质量递归压缩
     *
     * @param imgFile     源图片文件
     * @param maxkb       目标kb
     * @param photoWidth  目标宽度
     * @param photoHeight 模板高度
     * @param quality     质量
     * @return 处理后的文件byte[]
     * @throws Exception
     * @Title:compressPhoto
     * @Description: TODO
     * @date 2020年6月30日 下午2:11:52
     * @author yqwang
     */
    public byte[] compressPhoto(File imgFile, Integer maxkb, Integer photoWidth, Integer photoHeight, Float quality) throws Exception {
        // 1.压缩图片是否存在
        if (imgFile == null || !imgFile.exists()) {
            return null;
        }
        byte[] bytes = readFileToByteArray(imgFile);
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        // 2.是否超过100kb?没超过就不处理图片
        long fileSize = bytes.length;
        if (fileSize <= maxkb * size) {
            logger.info("图片不超过{}kb,无需压缩。", maxkb);
            return insertSgin(imgFile, bytes);
        }
        // 3.压缩
        BufferedImage bim = ImageIO.read(new ByteArrayInputStream(bytes));
        int imgWidth = 0;
        int imgHeight = 0;
        try {
            imgWidth = bim.getWidth();
            imgHeight = bim.getHeight();
        } catch (Exception e) {
            return null;
        }
        // 3.1.先按宽高判断是否需要缩放  outputQuality=1确保画质清晰
        if (imgWidth >= photoWidth && imgHeight >= photoHeight) {
            logger.info("先按宽{}高{}压缩。", photoWidth, photoHeight);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            Thumbnails.of(new ByteArrayInputStream(bytes)).size(photoWidth, photoHeight).outputQuality(1).outputFormat("jpg").toOutputStream(out);
            bytes = out.toByteArray();
        }
        // 3.2.判断按宽高缩放后是否超过100kb,超过递归就按质量压缩（图片会变得越来越模糊！）
        bytes = compressPhotoByQuality(bytes, quality, maxkb);
        return insertSgin(imgFile, bytes);
    }

    private byte[] insertSgin(File imgFile, byte[] bytes) throws IOException {
        createFile(bytes, path, imgFile.getName());
        Base64.Encoder encoder = Base64.getEncoder();
        try {
            SysUser sysUser = ISysUserService.getUserByLoginName(imgFile.getName().replaceAll("[.](.*)", ""));
            if (sysUser == null) {
                return bytes;
            }
            sysUser.setSign("data:image/png;base64," + encoder.encodeToString(bytes));
            ISysUserService.updateUser(sysUser);
        } catch (Exception e) {
            logger.error("存入签名失败{}", e);
        }
        return bytes;
    }

    public void createFile(byte[] data, String path, String fileName) throws IOException {
        FileImageOutputStream imageOutput = new FileImageOutputStream(new File(path + "/" + fileName));
        imageOutput.write(data, 0, data.length);
        imageOutput.close();
    }

    /**
     * 递归按quality质量处理，压缩到maxkb后返回新的bytes值
     *
     * @param bytes   源文件字节
     * @param quality 压缩质量 （如果>=1则不处理）
     * @param maxkb   要求压缩到的最大kb
     * @return
     * @throws IOException
     * @Title:compressPhotoByQuality
     * @Description: TODO
     * @date 2020年6月30日 下午2:24:36
     * @author yqwang
     */
    public static byte[] compressPhotoByQuality(byte[] bytes, Float quality, long maxkb) throws IOException {
        if (bytes == null) {
            return bytes;
        }
        logger.info("开始按质量压缩图片({}kb)。", bytes.length / 1024);
        // 如果配置的>=1，则不再处理,多说无益
        if (quality >= 1) {
            logger.info("quality>=1,不执行压缩。");
            return bytes;
        }
        // 满足目标kb值，则返回
        long fileSize = bytes.length;
        if (fileSize <= maxkb * size) {
            logger.info("图片文件{}kb<={}kb,不再压缩质量。", fileSize / 1024, maxkb);
            return bytes;
        }
        // Closing a <tt>ByteArrayOutputStream</tt> has no effect.   因此无需close
        ByteArrayOutputStream out = null;
        out = new ByteArrayOutputStream();
        BufferedImage bim = ImageIO.read(new ByteArrayInputStream(bytes));
        int imgWidth = bim.getWidth();
        int imgHeight = bim.getHeight();
        // 如果不处理size,只用quality,可能导致一致压缩不到目标值，一致递归在当前方法中！！
        int desWidth = new BigDecimal(imgWidth).multiply(new BigDecimal(quality)).intValue();
        int desHeight = new BigDecimal(imgHeight).multiply(new BigDecimal(quality)).intValue();
        logger.info("图片文将按照width={}*height={}进行压缩，画质quality={}。", desWidth, desHeight, quality);
        Thumbnails.of(new ByteArrayInputStream(bytes)).size(desWidth, desHeight).outputQuality(quality).outputFormat("jpg").toOutputStream(out);
        //递归
        return compressPhotoByQuality(out.toByteArray(), quality, maxkb);
    }

    /**
     * File to bytes[]
     */
    public static byte[] readFileToByteArray(File f) throws Exception {
        byte[] fileb = null;
        InputStream is = null;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            is = new FileInputStream(f);
            byte[] b = new byte[1024];
            int n;
            while ((n = is.read(b)) != -1) {
                out.write(b, 0, n);
            }
            fileb = out.toByteArray();
            return fileb;
        } catch (Exception var16) {
            throw new Exception("readFileToByteArray", var16);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (Exception var15) {
                    ;
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (Exception var14) {
                    ;
                }
            }
        }
    }
}
